﻿#ifndef METATYPE_H
#define METATYPE_H

#include <stdint.h>
#include <assert.h>
#include <string>
#include <iostream>
#include <functional>
#include <datastream.h>
#include <type_traits>

#include "ReflectX_global.h"
#include "typetrate.h"
#include "metatypedef_p.h"


#define ABSTRACT_CLASS virtual void __AbstractClass() = 0;

#define IMPLEMENT_CLASS void __AbstractClass() override{};

typedef std::vector<uint8_t> ByteArray;
class Reflectable;

class DataOutputStream;
class DataInputStream;
class StreamException;

class REFLECTX_EXPORT MetaType
{
public:
	enum TypeFlag {
		TF_None = 0,
		TF_PointerToReflectable,
		TF_Vector,
		TF_Map,



	};
    enum BasicType{
        BT_None = 0,
		BT_BOOL,
		BT_Char,
		BT_SChar,
		BT_UChar,
		BT_Int,
		BT_UInt,
		BT_Short,
		BT_UShort,
		BT_Long,
		BT_ULong,
		BT_LongLong,
		BT_ULongLong,
        BT_Float,
        BT_Double,
        BT_StdString,
        BT_StdWString,
        BT_ByteArray,
		BT_Size2F,
		BT_Size2I,
		BT_Size3F,
		BT_Size3I,
		BT_Point2F,
		BT_Point2I,
		BT_Point3F,
		BT_Point3I,
		BT_Rect2F,
		BT_Rect2I,
		BT_Rect3F,
		BT_Rect3I,
		BT_ColorF,
		BT_ColorI,
		BT_Image,
		BT_Variant,
        BT_VariantList,
        BT_VariantWMap,
        BT_VariantMap,
		BT_ReflectablePointer,


        Other,
    };

    typedef std::function<void(void*,void*)> convertFunction;

private:
    struct MetaTypeInfo
    {
        MetaTypeId id;

        std::string name;
        int size;
        void* (*defaultCreate)(void* mem);
        void* (*copyCreate)(void* mem,const void* other);
        void (*destory)(void* target);
        bool (*equalOperate)(void* o1,void* o2);
        void (*assign)(void* o1,const void* o2);
        void (*outputStream)(DataOutputStream*,const void*);
        void (*inputStream)(DataInputStream*,void*);
		TypeFlag flag;

		MetaTypeId vectorType = {};
		MetaTypeId mapKeyType = {};
		MetaTypeId mapValueType = {};

    };
public:
	template<typename T, typename Enable = void>
	class __GetTypeFlag
	{
	public:
		static constexpr TypeFlag flag = TypeFlag::TF_None;
	};

	template<typename T>
	class __GetTypeFlag<T, typename std::enable_if<std::is_pointer<T>::value && (std::is_base_of<Reflectable, typename std::remove_pointer<T>::type>::value || std::is_same<typename std::remove_pointer<T>::type, Reflectable>::value)>::type>
	{
	public:
		static constexpr TypeFlag flag = TypeFlag::TF_PointerToReflectable;
	};

	template<typename T>
	class __GetTypeFlag<std::vector<T>>
	{
	public:
		static constexpr TypeFlag flag = TypeFlag::TF_Vector;
	};

	template<typename K, typename V>
	class __GetTypeFlag<std::map<K, V>>
	{
	public:
		static constexpr TypeFlag flag = TypeFlag::TF_Map;
	};

	//一般类型
	template <typename T,typename Enabled = void>
	class __GetNameFromType
	{
	public:
		static std::string Get() {
			//static_assert(__TypeNameDecl<T>::vaild);
			return __TypeNameDecl<T>::Name;
		}

		static constexpr bool vaild = __TypeNameDecl<T>::vaild;
	};

	//Reflectable指针类型
	template <typename T>
	class __GetNameFromType < T, typename std::enable_if<std::is_pointer<T>::value && (std::is_base_of<Reflectable, typename std::remove_pointer<T>::type>::value || std::is_same<typename std::remove_pointer<T>::type, Reflectable>::value)>::type>
	{
	public:
		static std::string Get() {
            typedef typename std::remove_pointer<T>::type O;
			return std::string(O::ClassName) + "*";
		}

		static constexpr bool vaild = true;
	};

	//Map容器类型
	template<typename T>
	class __GetNameFromType < T, typename std::enable_if<IsMap<T>::value,void>::type>
	{
	public:
		static std::string Get() {
			std::string ret;
			ret += IsMap<T>::name;
			ret += "<";
			ret += __GetNameFromType<IsMap<T>::keyType>::Get();
			ret += ",";
			ret += __GetNameFromType<IsMap<T>::valueType>::Get();
			ret += ">";
			return ret;
		}

		static constexpr bool vaild = true;
	};

	//List容器类型
	template<typename T>
	class __GetNameFromType < T, typename std::enable_if<IsList<T>::value, void>::type>
	{
	public:
		static std::string Get() {
			std::string ret;
			ret += IsList<T>::name;
			ret += "<";
			ret += __GetNameFromType<IsList<T>::valueType>::Get();
			ret += ">";
			return ret;
		}

		static constexpr bool vaild = true;
	};

	template<typename ...Args>
	static std::vector<MetaTypeId> ToTypeList(ArgList<Args...> args) {
		return { MetaType::IdFromType<typename NormalizeType<Args>::Type>()... };
	}

public:
    MetaType();
    MetaType(MetaTypeId typeId);
    MetaType(std::string name);

    void* Create(void* buffer = NULL,const void* other = NULL);
    void Destory(void* target);
    void Delete(void* target);
    void Assign(void* target,const void* other);
    bool Equals(void* target,void* other);
    bool IsConvertable(int output_type);
    bool Convert(void* input,int output_type,void* output);
    bool hasStreamOperator() const;
    void Output(DataOutputStream& stream,const void* data);
    void Input(DataInputStream& stream,void* data) throw (StreamException);
    int Size();
    bool isValid();
    bool isNativeType() const;
	TypeFlag GetTypeFlag() const;
    bool isCustomType() const;
	bool isVector() const;
	MetaTypeId GetVectorValueType() const;
	bool isMap() const;
	MetaTypeId GetMapKeyType() const;
	MetaTypeId GetMapValueType() const;
	bool isPointerToReflectable() const;
    std::string Name() const;
	std::vector<std::string> Alias() const;
    MetaTypeId Id() const;
public:
	template<typename T>
	static MetaTypeId RegisterType() {
		typedef typename NormalizeType<T>::Type U;
		return RegisterType<T>(__GetNameFromType<U>::Get());
	}

    template<typename T>
    static MetaTypeId RegisterType(std::string name){
		typedef typename NormalizeType<T>::Type U;
        MetaTypeInfo info;

        info.id = 0;
        info.name = name;
        info.size = sizeof (U);
        info.assign = &GetAssignFunction<U>::Fun;
        info.copyCreate = &GetCopyConstruct<U>::Fun;
        info.defaultCreate = &GetDefaultConstruct<U>::Fun;
        info.destory = &GetDestructor<U>::Fun;
        info.equalOperate = &GetEqualFunction<U>::Fun;

		info.flag = __GetTypeFlag<U>::flag;

		RegisterMap<U>(info);
		RegisterVector<U>(info);

		_RegisterType(&info);

		RegisterReflectable<U>(info);
        return info.id;
    }

    static void UnRegisterType(std::string name);
    static void UnRegisterType(MetaTypeId typeId);

	//为类型注册别名
	template<typename T>
	static void RegisterAlias(const std::string name) {
		typedef typename NormalizeType<T>::Type U;
		RegisterAlias(IdFromType<U>(),name);
	}

	static void RegisterAlias(MetaTypeId type,const std::string name);

    template<typename T>
    class __IdFromType
    {
    public:
        static MetaTypeId Get(){
            static MetaTypeId id = []() {
                static_assert (__GetNameFromType<T>::vaild, "Error! Type Not Declared!");
                MetaTypeId ret = {};
                std::string className = __GetNameFromType<T>::Get();//获取类名
                ret = MetaType(className).Id();
                if (ret == BT_None) {//根据类名查找id，若id还未注册则进行注册
                    ret = RegisterType<T>(className);
                }
                return ret;
            }();

			return id;
        }
    };

    template<typename T>
    static MetaTypeId IdFromType(){
		typedef typename NormalizeType<T>::Type U;
        return __IdFromType<U>::Get();
    }

	

    template<typename T>
    static bool IsTypeDeclared(){
		typedef typename NormalizeType<T>::Type U;
		return __GetNameFromType<U>::vaild;
    }

    template<typename In,typename Out>
    static void RegisterConvertor(){
		typedef typename NormalizeType<In>::Type InU;
		typedef typename NormalizeType<Out>::Type OutU;
        RegisterConvertor<InU, OutU>([](const InU in, OutU& out){
            out = in;
        });
    }

    template<typename In,typename Out>
    static void RegisterConvertor(std::function<void(const In&,Out&)> func){
		typedef typename NormalizeType<In>::Type InU;
		typedef typename NormalizeType<Out>::Type OutU;
        if(!MetaType::IsTypeDeclared<InU>()){
            std::cout<<"type not Declared!"<<std::endl;
            return;
        }

        if(!MetaType::IsTypeDeclared<OutU>()){
            std::cout<<"type not Declared!"<<std::endl;
        }

        RegisterConvertor(IdFromType<InU>(),IdFromType<OutU>(),[=](void* in,void* out){
            func(*(InU*)in,*(OutU*)out);
        });
    }

	static void RegisterConvertor(MetaTypeId in_type, MetaTypeId out_type, convertFunction func);

    template<typename T>
    static void RegisterStreamOperator(){
		typedef typename NormalizeType<T>::Type U;
        MetaTypeId id = MetaType::IdFromType<U>();
        if(id == 0){
            std::cerr << "error type is Not Registered!" <<std::endl;
            return;
        }
        auto output = [](DataOutputStream* s,const void* val){
            (*s) << *(const U*)val;
        };
        auto input = [](DataInputStream* s,void* val){
            (*s) >> *(U*)val;
        };
        RegisterStreamOperator(id,output,input);
    }

	template<typename T>
	static typename std::enable_if<__GetTypeFlag<T>::flag == TypeFlag::TF_PointerToReflectable>::type RegisterReflectable(MetaTypeInfo& info) {
		MetaType::RegisterConvertor(info.id, MetaType::BT_ReflectablePointer, [](void*o1, void*o2) {
			T in = *(T*)o1;
			Reflectable* out = in;
			*(Reflectable**)o2 = out;
		});

		MetaType::RegisterConvertor(MetaType::BT_ReflectablePointer, info.id, [](void*o1, void*o2) {
			Reflectable* in = *(Reflectable**)o1;
			T out = dynamic_cast<T>(in);
			*(T*)o2 = out;
		});
	}

	template<typename T>
	static typename std::enable_if<__GetTypeFlag<T>::flag != TypeFlag::TF_PointerToReflectable>::type RegisterReflectable(MetaTypeInfo& info) {

	}

	template<typename T>
	static typename std::enable_if<__GetTypeFlag<T>::flag == TypeFlag::TF_Map>::type RegisterMap(MetaTypeInfo& info) {
        info.mapValueType = IdFromType<typename T::value_type::second_type>();
		info.mapKeyType = IdFromType<typename std::remove_const<typename T::value_type::first_type>::type>();
	}

	template<typename T>
	static typename std::enable_if<__GetTypeFlag<T>::flag != TypeFlag::TF_Map>::type RegisterMap(MetaTypeInfo& info) {

	}

	template<typename T>
	static typename std::enable_if<__GetTypeFlag<T>::flag == TypeFlag::TF_Vector>::type RegisterVector(MetaTypeInfo& info) {
        info.vectorType = IdFromType<typename T::value_type>();
	}

	template<typename T>
	static typename std::enable_if<__GetTypeFlag<T>::flag != TypeFlag::TF_Vector>::type RegisterVector(MetaTypeInfo& info) {

	}

    static MetaTypeId _RegisterType(MetaTypeInfo* metainfo);
    struct Private;
    friend struct Private;
    static Private* Instance_P();
    static void FinishNativeType();
    static MetaTypeInfo FindInfo(MetaTypeId typeId);
	static MetaTypeInfo FindInfo(std::string name);

	static MetaTypeInfo FindInfo_nolock(MetaTypeId typeId);
	static MetaTypeInfo FindInfo_nolock(std::string name);

	static std::vector<std::string> FindAlias(MetaTypeId typeId);

    static void RegisterStreamOperator(MetaTypeId id,void(*output)(DataOutputStream*,const void* val),void (*input)(DataInputStream*,void* val) throw(StreamException));
private:
    MetaTypeId typeId;
    class Initialize;
    friend class Initialize;
};

template<>
class MetaType::__IdFromType<void>
{
public:
    static MetaTypeId Get(){
        return 0;
    }
};

#define REGISTER_META_TYPE(typeName) \
MetaType::RegisterType<typeName>(#typeName);

#define REGISTER_ALIAS(alias) \
MetaType::RegisterAlias<alias>(#alias);

#endif // METATYPE_H
